/*
 * PublicGoods.java
 *
 * Implements the Public-Goods game.
 */

package game;

import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.MemoryImageSource;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.util.Random;
import javax.swing.Timer;

/**
 * Participants choose to contribute their endowment to a common pot or not.
 * The pot is doubled, and the money is evenly distributed to everyone.
 *
 * @author Justin
 */
public class PublicGoods extends Game {
	/** The amount of time, in seconds, available for the game. */
    final int GAME_TIME = 180;
	/** Timer for the game countdown. */
    Timer timer = new Timer (1000, new TimeListener());

	/** Amount of money all players are given. */
	private double endowment;
	/** Number of participants (not including subject). */
	private int participants;

	/** Amount of money player has. */
	private double money;
	/** Size of community pot. */
	private double pot;
	/** How much money someone who didn't contribute gets. */
	private double oppMoney;

	// End game constants.
	final int EG_NORMAL = 0;
	final int EG_TIMEOUT = 1;

    public PublicGoods (String params, int currentRep) {
		super();
        initComponents();
        this.setVisible (true);
        hideMouse();

        secs = GAME_TIME;
        timer.start();
        updateTimerLabel();

		String paramPart[] = params.split (",");
		participants = Integer.parseInt(paramPart[2]);
		endowment = Double.parseDouble(paramPart[3]);
		this.params = params;
		repTot = Integer.parseInt (paramPart[1]);
		repNum = currentRep;

		money = endowment;
		pot = 0;
		moneyLabel.setText ("You have " + String.format("$%.2f", money) + ".");

        runner.addMouseListener (new PublicGoods.CheckMouse());
        this.addMouseListener (new PublicGoods.CheckMouse());
		this.getGlassPane().addMouseListener(new PublicGoods.CheckMouse());
	}

	// GAME --------------------------------------------------------------------
	/**
	 * Calculates the payout that the subject gets. For each player other than
	 * the subject, randomly choose whether to contribute endowment. Then
	 * calculate the new pot size, and redistribute the pot.
	 *
	 * @param subjectContribs	Whether the subject contributes to the pot.
	 */
	private void calculateResult (boolean subjectContribs) {
		Random random = new Random();
		int numContribs = random.nextInt(participants+1);
		System.err.println ("[DEBUG]: " + numContribs + " others contributed.");

		writeGameLog ("" + (GAME_TIME-secs) + "," + (subjectContribs? 1 : 0)
			+ "," + numContribs);

		if (subjectContribs) {
			pot += money;
			money = 0;
		}
		pot += numContribs*endowment;
		pot *= 2;
		money += pot/(participants+1);

		// Calculate how much money someone who made the opposite decision made,
		// unless everyone made the same decision.
		if (subjectContribs) {
			if (numContribs == participants)
				oppMoney = money;
			else
				oppMoney = endowment + money;
		}
		else {
			if (numContribs == 0)
				oppMoney = money;
			else
				oppMoney = money - endowment;
		}

		endGame (EG_NORMAL);
	}

	/**
     * Ends the game, writes to log file.
     */
    private void endGame (int status) {
		totalMoneyWon += money;

		String payment = "";
		String oppPay = "";
		
		if (status == EG_NORMAL) {
			payment = String.format("$%.2f", money);
			oppPay = String.format("$%.2f", oppMoney);
		}
		else if (status == EG_TIMEOUT) {
			payment = "TimeOut";
			oppPay = "TimeOut";
		}
		writeLog (playerId + ",,\"" + params + "\"," + repNum + "," + repTot
			+ "," + payment + "," + oppPay);

		setVisible(false);
		free = true;
    }

	// LISTENERS ---------------------------------------------------------------
	/**
     * Defines what we do when the user clicks the mouse.
     */
    class CheckMouse implements MouseListener{
        public void mousePressed (MouseEvent e) { hideMouse(); }
        public void mouseReleased (MouseEvent e) {}
        public void mouseEntered (MouseEvent e) {}
        public void mouseExited (MouseEvent e) {}

		/**
         * Handle mouse clicks.
         *
         * @param e The MouseEvent.
         */
		public void mouseClicked (MouseEvent e){
            int modifiers = e.getModifiers();
			
			// Left click (no contribution).
			if ((modifiers & InputEvent.BUTTON1_MASK) ==
					InputEvent.BUTTON1_MASK) {
				calculateResult (false);
			}

			// Right click (contributes endowment).
			else if ((modifiers & InputEvent.BUTTON3_MASK) ==
					InputEvent.BUTTON3_MASK) {
				pot += money;
				money = 0;
				calculateResult (true);
			}

			// Invalid input.
			else {
				// Do nothing.
			}
        }
    }

	/**
     * Handles timer actions.
     */
    class TimeListener implements ActionListener {
    	/**
         * Decrement the time remaining, if there is any. If the user has run
         * out of time, then exit.
         *
         * @param e The ActionEvent.
         */

        public void actionPerformed(ActionEvent e) {
            if (secs > 0) {
                secs--;
                updateTimerLabel();
            }
            else {
                timer.stop();
                descLabel.setText ("Sorry, your time is up.");
                endGame (EG_TIMEOUT);
            }
    	}
    }

	// LAYOUT & APPEARANCE -----------------------------------------------------
	/**
     * Based on the time remaining, updates the time remaining label.
     */
    private void updateTimerLabel() {
        int min = secs / 60;
        int sec = secs % 60;
        timeLabel.setText (min + ":" + ((sec < 10) ? "0" : "") + sec);
    }

    /**
     * Hides the mouse so the user can't see it.
     */
    private void hideMouse() {
        int[] pixels = new int[16 * 16];
        Image image = Toolkit.getDefaultToolkit().createImage(
				new MemoryImageSource(16, 16, pixels, 0, 16));
        Cursor transparentCursor = Toolkit.getDefaultToolkit()
				.createCustomCursor(image, new Point(0, 0), "invisibleCursor");
        this.getGlassPane().setCursor(transparentCursor);
		this.getGlassPane().setVisible(true);
        runner.setCursor(transparentCursor);
    }

	// GENERATED CODE AND MAIN -------------------------------------------------
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        timeLabel = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        moneyLabel = new javax.swing.JLabel();
        descLabel = new javax.swing.JLabel();
        lblYes = new javax.swing.JLabel();
        lblNo = new javax.swing.JLabel();

        setBackground(new java.awt.Color(255, 255, 255));
        setBorder(null);
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setMaximumSize(new java.awt.Dimension(800, 600));
        setMinimumSize(new java.awt.Dimension(800, 600));
        setPreferredSize(new java.awt.Dimension(800, 600));

        timeLabel.setFont(new java.awt.Font("Calibri", 1, 36)); // NOI18N
        timeLabel.setForeground(new java.awt.Color(153, 102, 0));
        timeLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/hrGlass.png"))); // NOI18N
        timeLabel.setText("3:00");

        jLabel1.setFont(new java.awt.Font("Calibri", 1, 28)); // NOI18N
        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Public Goods");

        moneyLabel.setFont(new java.awt.Font("Calibri", 0, 28)); // NOI18N
        moneyLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        moneyLabel.setText("You have $.");

        descLabel.setFont(new java.awt.Font("Calibri", 0, 24)); // NOI18N
        descLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        descLabel.setText("<html>Would you like to contribute this money to the community pot, so that it can be doubled and distributed evenly to each member of the group?</html>");

        lblYes.setFont(new java.awt.Font("Calibri", 1, 24)); // NOI18N
        lblYes.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblYes.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/greenNo.png"))); // NOI18N

        lblNo.setFont(new java.awt.Font("Calibri", 1, 24)); // NOI18N
        lblNo.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblNo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/redYes.png"))); // NOI18N

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(timeLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
            .add(jLabel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
            .add(moneyLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap(94, Short.MAX_VALUE)
                .add(descLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 610, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(96, 96, 96))
            .add(layout.createSequentialGroup()
                .add(106, 106, 106)
                .add(lblYes, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 233, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 119, Short.MAX_VALUE)
                .add(lblNo)
                .add(109, 109, 109))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(timeLabel)
                .add(40, 40, 40)
                .add(jLabel1)
                .add(51, 51, 51)
                .add(moneyLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(descLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 132, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 85, Short.MAX_VALUE)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(lblYes)
                    .add(lblNo))
                .add(82, 82, 82))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel descLabel;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel lblNo;
    private javax.swing.JLabel lblYes;
    private javax.swing.JLabel moneyLabel;
    private javax.swing.JLabel timeLabel;
    // End of variables declaration//GEN-END:variables

}
